iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0

嗨我是k66,前篇已將UEFI開機畫面完成,從bootloader到kernel,本篇我們在kernel內寫個猜拳遊戲!
https://ithelp.ithome.com.tw/upload/images/20231003/20161828Z1eLQpHrqG.png
https://ithelp.ithome.com.tw/upload/images/20231003/201618287KnDHmTC2T.png
https://ithelp.ithome.com.tw/upload/images/20231003/20161828YDBPPZT1Tz.png
https://ithelp.ithome.com.tw/upload/images/20231003/20161828xZ8kLTivNk.png

放碼上來!程式碼連結


  • Entry.c內的BootMenu(),執行Kernel1時就能玩猜拳遊戲。

  • 猜拳遊戲 PaperScissorsStone.c

#include<Entry.h>

void Paper()
{

Print(L"               _\n");
Print(L"           _  | |  _\n");
Print(L"          | | | | | |\n");
Print(L"    ___   | | | | | |   __\n");
Print(L"    \\  \\  | | | | | |  / / \n");
Print(L"     \\  \\_| |_| |_| |_/ / \n");
Print(L"      \\                 |\n");
Print(L"       \\                /   \n");
Print(L"        \\______________/\n");
}

void Scissors()
{
Print(L"      ___       ___ \n");
Print(L"     /    \\    /   \\\n");
Print(L"    /      \\__/     \\\n");
Print(L"    |                |\n");
Print(L"    |                |\n");
Print(L"     \\____      ____/\n");
Print(L"          |    |\n");
// Print(L"          |____|\n");
}


void Stone()
{

Print(L"        _________________\n");
Print(L"       /  |  |   |   |   \\\n");
Print(L"      /   |  |   |   |    \\\n");
Print(L"     |                     |\n");
Print(L"     |                     |\n");
Print(L"      \\                   /\n");
Print(L"       \\_________________/\n");
Print(L"\n");

}


CHAR16 RANDOM_CHOOSE(UINT8 dirty)
{
  IoWrite8(CMOS_ADDRESS,0x00);
  UINT8 randNo = ( dirty+IoRead8(CMOS_DATA) )%3;
  if(randNo==0)
    return 'P';
  else if(randNo==1)
    return 'S';
  else
    return 'O';
}


EFI_STATUS EFIAPI PaperScissorsStone()
{
  // Initialize the screen
  EFI_STATUS Status;
  Status = EFI_SUCCESS;
  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop=NULL;
  Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID**) &Gop);
  if (EFI_ERROR(Status)) {
    Print(L"Unable to locate Graphics Output Protocol\n");
    Print(L"Press any key to exit...\n");
    UINTN EventIndex;
    gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &EventIndex);
    Exit(1);
  }
  
  Print(L"P(Paper), S(Scissors), O(Stones)\n");
  Print(L"++++++++++++++++++++++++++++++++\n");
  
  CHAR16 enemyKey = 'P';
  
  //Main loop
  BOOLEAN Stop = FALSE;
  UINT8 cnt = 0;
  UINT8 youWin = 0;
  UINT8 enemyWin = 0;
  EFI_INPUT_KEY playerKey;
  Print(L"Press ESC to leave the game...\n");
  while(!Stop){
    //Check for keys event
    Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &playerKey);
    while(1)
    {
      Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &playerKey);
      if(playerKey.ScanCode==SCAN_ESC)
      {
        Stop=TRUE;
        break;
      }
      if( Status==EFI_SUCCESS )
      {

        /* enemy 隨機選一種:剪刀/石頭/布 */
        cnt+=1;
        enemyKey = RANDOM_CHOOSE(cnt);
        
        gST -> ConOut -> SetAttribute(gST->ConOut,0x0); // 白色 
        
        /* Player green */
        gST -> ConOut -> SetAttribute(gST->ConOut,0x2); 
        Print(L"(You) \n");
        switch(playerKey.UnicodeChar)
        {
            case 'P':
              Paper();
            case 'S':
              Scissors();
            case 'O':
              Stone();
        }

        /* Enemy Red */
        gST -> ConOut -> SetAttribute(gST->ConOut,0x4);
        Print(L"(Enemy) \n");
        switch(enemyKey)
        {
            case 'P':
              Paper();
            case 'S':
              Scissors();
            case 'O':
              Stone();
        }

        // 猜拳
        Print(L"The %d game result: \n", cnt);
        gST -> ConOut -> SetAttribute(gST->ConOut,0x0); // 白色 
        if( playerKey.UnicodeChar == enemyKey )
            Print(L"Tie\n");
        
        else if (  (playerKey.UnicodeChar=='S'&&enemyKey=='P')  ||
                   (playerKey.UnicodeChar=='O'&&enemyKey=='S') ||
                   (playerKey.UnicodeChar=='P'&&enemyKey=='O')
                ){
            Print(L"You Win\n");
            youWin+=1;
        }

        else{
            Print(L"You Lose\n");
            enemyWin+=1;
        }


        Print(L"Win %d times\n",youWin);
        Print(L"Lose %d times\n",enemyWin);
        Print(L"Tie %d times\n",cnt-youWin-enemyWin);
        Print("==========================\n");
        Print("==========================\n");


        if(cnt%3==0)
          gST -> ConOut -> SetAttribute(gST->ConOut,0x1);//每玩3局完畢,需清空螢幕
      } // if Status success
    }//while
    
  }

  Print(L"Game over !\n ctrl+C to exit...\n");
  
  return EFI_SUCCESS;
}

總結

本日完成UEFI猜拳遊戲,結合日前完成的開機畫面,從OinkBootloader至kernel(OS)。目前寫法都塞在一個檔案是為了盡量確保讀者能成功執行,未來會模組化之。本系列文快結束了,筆者正在考慮剩下三篇文需不需要介紹一些Debug技巧,歡迎提供我想法~


上一篇
【Day 26】自己寫的UEFI開機畫面—設定螢幕解析度
下一篇
【Day 28】實體機跑自己寫的UEFI開機畫面
系列文
世界第一簡單的UEFI,實作打造自己的開機畫面31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言